package server.threads;

import java.util.ArrayList;
import java.util.HashMap;

import server.Connection;
import server.ConnectionMap;
import server.Server;
import server.communication.listeners.AddServerRequestListener;
import server.communication.listeners.AuthenticationListener;
import server.communication.listeners.BulkUpdateRequestListener;
import server.communication.listeners.BulkUpdateResponseListener;
import server.communication.listeners.InsertDataListener;
import server.communication.listeners.PingListener;
import server.communication.listeners.RestartListener;
import server.communication.listeners.ShutDownListener;
import server.communication.listeners.UpdateDataListener;

import communication.Communicator;
import communication.MessageReceivedEvent;

import message.Message;

public class ServerCommunicator extends Communicator
{
	private final ConnectionMap connections;
	private final Server server;
	private boolean running;
	
	public ServerCommunicator(Server server, ConnectionMap connections)
	{
		this.server = server;
		this.connections = connections;
		this.running = true;
		
		this.addListener(new AuthenticationListener(this, server.getAccountRepository()));
		this.addListener(new InsertDataListener(this, server));
		this.addListener(new UpdateDataListener(this, server));
		this.addListener(new RestartListener(this, server));
		this.addListener(new ShutDownListener(this, server));
		this.addListener(new PingListener(this));
		this.addListener(new AddServerRequestListener(server));
		this.addListener(new BulkUpdateRequestListener(this, server.getAccountRepository()));
		this.addListener(new BulkUpdateResponseListener(server));
	}
	
	public int getAvailableConnectionId()
	{
		for (int i = 0; i < Integer.MAX_VALUE; i++)
		{
			if (connections.get(i) == null)
				return i;
		}
		
		return -1;
	}
	public void broadcastToServers(Message message)
	{
		Connection[] serverConnections = this.connections.serverConnectionValues().toArray(new Connection[0]);
		System.out.println("Server count: " + serverConnections.length);
		for (Connection connection : serverConnections)
		{
			connection.sendMessage(message);
		}
	}
	public void sendMessage(int connectionId, Message message)
	{
		System.out.println(message);
		Connection connection = connections.get(connectionId);
		
		if (connection != null)
			connection.sendMessage(message);
	}
	public void stopRunning()
	{
		running = false;
	}
	public void run()
	{
		try
		{
			while (running)
			{
				Connection[] connections = this.connections.values().toArray(new Connection[0]);
				
				for (Connection connection : connections)
				{
					if (connection.hasMessage())
					{
						Message message = connection.getMessage();
						
						MessageReceivedEvent event = new MessageReceivedEvent(message);
						
						System.out.println("Message received.");
						
						delegateMessageEvent(event);
					}
				}
				
				try
				{
					Thread.sleep(100); // Sleep for 1/10 a second to keep the server from using 100% processor
				}
				catch (InterruptedException e) {} 
			}
		}
		catch (Throwable t) { server.uncaughtThrowableThrown(t); }
	}

	public int getConnectionCount()
	{
		return connections.size();
	}
}
